package cos.android.tim.utils;

import cos.android.tim.element.Element;
import cos.android.tim.objects.Elements;
import cos.android.tim.objects.Rampa;

public class Motor {

	public static void colision(Element element1, Element element2) {

		if (element1.isDinamicElement() || element2.isDinamicElement()) {
			if (colisionPolygonPolygon(element1, element2)) {

			}
		}
		/*
		 * if (element1.isDinamicElement() && element2.isDinamicElement()) {
		 * dinamicDinamicColision(element1, element2); } else if
		 * (element1.isDinamicElement()) { dinamicStaticColision(element1,
		 * element2); } else if (element2.isDinamicElement()) {
		 * dinamicStaticColision(element2, element1); }
		 */

	}

	public static boolean colisionPolygonPolygon(Element dinamicPolygon,
			Element staticPolygon) {

		double minDistance = 9999;
		double deeper = 0;
		Point p1 = null;

		for (Point arista : dinamicPolygon.getAristas()) {

			if (staticPolygon.collition(arista)) {

				for (int i = 0; i < staticPolygon.getAristas().size() - 1; i++) {

					double aux = Motor.pointLineDistance(arista, staticPolygon
							.getAristas().elementAt(i), staticPolygon
							.getAristas().elementAt(i + 1));
					if (aux < minDistance) {
						minDistance = aux;
					}
				}

				if (minDistance > deeper) {
					p1 = arista;
				}
			}
		}
		if (p1 != null) {
			reaction(staticPolygon, dinamicPolygon, p1);
			staticPolygon.setLastHitted(dinamicPolygon);
			dinamicPolygon.setLastHitted(staticPolygon);
			return true;

		}

		for (Point arista : staticPolygon.getAristas()) {

			if (dinamicPolygon.collition(arista)) {

				for (int i = 0; i < dinamicPolygon.getAristas().size() - 1; i++) {

					double aux = Motor.pointLineDistance(arista, dinamicPolygon
							.getAristas().elementAt(i), dinamicPolygon
							.getAristas().elementAt(i + 1));
					if (aux < minDistance) {
						minDistance = aux;
					}
				}

				if (minDistance > deeper) {
					p1 = arista;
				}
			}
		}
		if (p1 != null) {
			reaction(dinamicPolygon, staticPolygon, p1);
			dinamicPolygon.setLastHitted(staticPolygon);
			staticPolygon.setLastHitted(dinamicPolygon);
			return true;

		}
		return false;

	}

	private static void reaction(Element polygon, Element polygon2, Point arista) {
		double minDistance = 9999;
		int p1 = 0;
		for (int i = 0; i < polygon.getAristas().size() - 1; i++) {

			double aux = Motor.pointLineDistance(arista, polygon.getAristas()
					.elementAt(i), polygon.getAristas().elementAt(i + 1));
			if (aux < minDistance) {
				minDistance = aux;
				p1 = i;

			}
		}

		Point point1 = polygon.getAristas().elementAt(p1);
		Point point2 = polygon.getAristas().elementAt(p1 + 1);

		float previousSpeedx = 0;
		float previousSpeedy = 0;

		double m2 = 0;
		if (polygon2.getoX() == 0) {
			m2 = Math.atan2(0, 1);
		} else {
			m2 = Math.atan(polygon2.getoX() / polygon2.getoY());
		}

		double m = 0;
		if (point1.getxPos() - point2.getxPos() == 0) {
			previousSpeedx = (float) (-polygon2.getoX());
			previousSpeedy = (float) (-polygon2.getoY());
		} else if (point1.getyPos() - point2.getyPos() == 0) {

			previousSpeedx = (float) (polygon2.getoX());
			previousSpeedy = (float) (polygon2.getoY());

		} else {

			m = Math.atan2((point2.getyPos() - point1.getyPos()),
					(point2.getxPos() - point1.getxPos()));

			// System.out.println("m: " + m);
			previousSpeedx = (float) ((polygon2.getSpeed() + polygon.getSpeed()) * Math
					.sin(m + m2));
			previousSpeedy = (float) ((polygon2.getSpeed() + polygon.getSpeed()) * Math
					.cos(m + m2));
		}

		// System.out.println(arista.toString());
		// System.out.println(polygon2.toString());
		if (polygon2.isDinamicElement()) {
			polygon2.setxPos((float) (polygon2.getxPos() - Math.sin(m)
					* minDistance));
			polygon2.setyPos((float) (polygon2.getyPos() - Math.cos(m)
					* minDistance));
		}
		if (polygon.isDinamicElement()) {
			polygon.setxPos((float) (polygon.getxPos() - Math.sin(m)
					* minDistance));
			polygon.setyPos((float) (polygon.getyPos() - Math.cos(m)
					* minDistance));
		}

		/*
		 * System.out.println("m: " + m + " m2: " + m2);
		 * System.out.println("Puntos: " + point1.toString() + " " +
		 * point2.toString());
		 */
		// System.out.println("Antes speed1: " + polygon2.getoX());
		polygon2.reset();

		switch (Elements.valueOf(polygon.getKind())) {
		case Punch:
			if (point1.getyPos() == point2.getyPos()) {
				polygon.action();
			}
			break;
		case Batery:
			polygon.action();
			break;
		case Radio:
			polygon.action();
		}

		if (polygon.getKind() == "Trampoline" && m == 0) {
			polygon2.applySpeed(previousSpeedx * 1.1f, -previousSpeedy * 1.1f);
		} else {

			polygon2.applySpeed(previousSpeedx,
					-previousSpeedy * polygon2.getFlexibility());
			//System.out.println("speed1: " + polygon2.getoX());
		}
		if (polygon2.getKind() == "Trampoline" && m == 0) {
			polygon.applySpeed(previousSpeedx * 1.1f, previousSpeedy * 1.1f);
		} else {
			// System.out.println("Antes speed2: " + polygon.getoX());

			polygon.applySpeed(-previousSpeedx,
					previousSpeedy * -polygon.getFlexibility());
			// System.out.println("speed2: " + polygon.getoX());
		}

		if (Math.abs(polygon2.getoY()) < 40) {
			polygon2.resetY();
		}
		/*
		 * if (Math.abs(polygon2.getoX()) < 20) { polygon2.resetX(); }
		 */
		if (Math.abs(polygon.getoY()) < 40) {
			polygon.resetY();
		}
		/*
		 * if (Math.abs(polygon.getoX()) < 20) { polygon.resetX(); }
		 */

	}

	/*
	 * DinamicElement circle2 = null; Element square2 = (Element) square; if
	 * (circle instanceof DinamicElement) { circle2 = (DinamicElement) circle;
	 * if (circle2.getLastHited() != square) {
	 * 
	 * // Colision horizontal if ((circle.getCenterX() > square2.getxPos()) &&
	 * (circle.getCenterX() < square2.getxPos() + square2.getWidth()) &&
	 * circle.getCenterY() + circle.getRadius() >= square2 .getyPos()) {
	 * 
	 * circle2.applyForce(0, ((-circle2.getoY()) + (-circle2 .getoY() *
	 * circle2.getFlexibility())));
	 * 
	 * circle2.setLastHited(square2); return true; } else // Colision esquina
	 * izquierda if ((circle.getCenterX() < square2.getxPos()) &&
	 * (circle.getCenterX() + circle.getRadius() > square2 .getxPos()) &&
	 * circlePointDistance(circle, square2.getxPos(), square2.getyPos()) <
	 * circle.getRadius()) {
	 * 
	 * float dxb = Math.abs(circle.getCenterX() - square2.getxPos()); float dyb
	 * = Math.abs(circle.getCenterY() - square2.getyPos());
	 * 
	 * float propY = (dyb / (dxb + dyb)); float propX = 1 - propY;
	 * 
	 * circle2.applyForce( -circle2.getSpeed() * propX circle2.getFlexibility(),
	 * -(Math.abs(circle2.getoY()) + circle2.getSpeed() propY *
	 * circle2.getFlexibility())); circle2.setLastHited(square2); return true; }
	 * else
	 * 
	 * // Colision esquina derecha if ((circle.getCenterX() > square2.getxPos()
	 * + square2.getWidth()) && (circle.getCenterX() - circle.getRadius() <
	 * square2 .getxPos() + square2.getWidth()) && circlePointDistance(circle,
	 * square2.getxPos() + square2.getWidth(), square2.getyPos()) < circle
	 * .getRadius()) {
	 * 
	 * float dxb = Math.abs(circle.getCenterX() - square2.getxPos() +
	 * square2.getWidth()); float dyb = Math.abs(circle.getCenterY() -
	 * square2.getyPos());
	 * 
	 * float propY = (dyb / (dxb + dyb)); float propX = 1 - propY;
	 * 
	 * circle2.applyForce( circle2.getSpeed() * propX circle2.getFlexibility(),
	 * -(Math.abs(circle2.getoY()) + circle2.getSpeed() propY *
	 * circle2.getFlexibility())); circle2.setLastHited(square2); return true;
	 * 
	 * } else
	 * 
	 * // Colision Vertical if ((circle.getCenterY() > square2.getyPos()) &&
	 * (circle.getCenterY() < square2.getyPos() + square2.getHeight()) &&
	 * circle.getCenterX() + circle.getRadius() >= square2 .getxPos() &&
	 * circle.getCenterX() - circle.getRadius() < square2 .getxPos() +
	 * square2.getWidth()) { circle2.applyForce( circle2.getoX() * -2 *
	 * circle2.getFlexibility(), 0);
	 * 
	 * circle2.setLastHited(square2); return true; } }
	 * 
	 * } else { return false; }
	 */

	public static boolean correct(Element element1, Element element2) {

		if (element1.checkCollision(element2)) {
			return true;
		}
		return false;
	}

	public static double circleDistance(Element circle1, Element circle2) {

		return Math.sqrt(Math.pow(circle1.getCenterX() - circle2.getCenterX(),
				2) + Math.pow(circle1.getCenterY() - circle2.getCenterY(), 2));

	}

	public static double circleRampaDistance(Element circle, Rampa rampa) {

		Element rampa1 = (Element) rampa;

		double b = rampa1.getyPos() - rampa.getM() * rampa1.getxPos();
		double aux = (Math.abs(rampa.getM() * circle.getCenterX()
				- circle.getCenterY() + b))
				/ (Math.sqrt(Math.pow(rampa.getM(), 2) + 1));
		return aux - circle.getRadius();
	}

	public static double circleLineDistance(Element circle, Point point1,
			Point point2) {

		if (point1.getxPos() - point2.getxPos() == 0) {
			return (Math.min(
					circlePointDistance(circle, point1) - circle.getRadius(),
					circlePointDistance(circle, point2) - circle.getRadius()));
		} else {
			double m = ((point1.getyPos() - point2.getyPos()) / (point1
					.getxPos() - point2.getxPos()));

			double b = point1.getyPos() - m * point1.getxPos();
			double aux = (Math.abs(m * circle.getCenterX()
					- circle.getCenterY() + b))
					/ (Math.sqrt(Math.pow(m, 2) + 1));
			double distance = aux - circle.getRadius();
			return distance;
		}
	}

	public static double pointLineDistance(Point point, Point point1,
			Point point2) {
		if (point1.getxPos() - point2.getxPos() == 0) {
			return (pointPointDistance(point,
					new Point(point1.getxPos(), point.getyPos())));
		} else {
			double m = ((point1.getyPos() - point2.getyPos()) / (point1
					.getxPos() - point2.getxPos()));

			double b = point1.getyPos() - m * point1.getxPos();
			double aux = (Math.abs(m * point.getxPos() - point.getyPos() + b))
					/ (Math.sqrt(Math.pow(m, 2) + 1));
			double distance = aux;
			return distance;
		}
	}

	public static double circlePointDistance(Element circle, float x, float y) {

		return Math.sqrt(Math.pow(circle.getCenterX() - x, 2)
				+ Math.pow(circle.getCenterY() - y, 2));

	}

	public static double circlePointDistance(Element circle, Point point) {

		return Math.sqrt(Math.pow(circle.getCenterX() - point.getxPos(), 2)
				+ Math.pow(circle.getCenterY() - point.getyPos(), 2));

	}

	public static double pointPointDistance(float x1, float x2, float y1,
			float y2) {

		return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));

	}

	public static double pointPointDistance(Point point1, Point point2) {
		return Math.sqrt(Math.pow(point1.getxPos() - point2.getxPos(), 2)
				+ Math.pow(point1.getyPos() - point2.getyPos(), 2));

	}

}
